package com.kalvan.log.logback;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.lang.StringUtils;
import org.slf4j.impl.StaticLoggerBinder;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.selector.ContextSelector;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.classic.util.ContextSelectorStaticBinder;
import ch.qos.logback.core.joran.spi.JoranException;

/**
 * 
 * 日志框架spring 集成
 * 
 * @author chenliang
 * @version 2018年4月17日
 * @see LogbackBoot
 *
 */
public class LogbackBoot  {
	public static final String LOGPATH = "logback.logpath";
	public static final String ROOTLOGGER_LEVEL = "logback.rootLoggerLevel";
	public static final String MAXFILESIZE = "logback.maxFileSize";
	public static final String LOGBACKPROPERTIES = "logbackProperties";
	/** Pseudo URL prefix for loading from the class path: "classpath:" */
	public static final String CLASSPATH_URL_PREFIX = "classpath:";

	/**
	 * 日志路径
	 */
	private String logpath;
	/**
	 * 日志级别
	 */
	private String rootLoggerLevel;
	/**
	 * 日志文件分隔大小
	 */
	private String maxFileSize;
	/**
	 * 日志格式模板配置文件
	 */
	private String logbackConfigLocation;

	public String getLogpath() {

		return logpath;
	}

	public void setLogpath(String logpath) {
		this.logpath = logpath;
	}

	public String getRootLoggerLevel() {

		return rootLoggerLevel;
	}

	public void setRootLoggerLevel(String rootLoggerLevel) {
		this.rootLoggerLevel = rootLoggerLevel;
	}

	public String getMaxFileSize() {

		return maxFileSize;
	}

	public void setMaxFileSize(String maxFileSize) {
		this.maxFileSize = maxFileSize;
	}

	public String getLogbackConfigLocation() {

		return logbackConfigLocation;
	}

	public void setLogbackConfigLocation(String logbackConfigLocation) {
		this.logbackConfigLocation = logbackConfigLocation;
	}

	/**
	 * 注入动态配置属性<br>
	 * 编码默认是utf-8 <br>
	 * 输出格式统一%date{yyyy-MM-dd HH:mm:ss.SSS}|%-5level
	 * |%t:%threadid|%logPreFix|%class.%method:%line|%sensitiveMsg%n
	 */
	public void init() throws Exception {
		if (StringUtils.isNotBlank(logpath)) {
			System.setProperty(LOGPATH, logpath.trim());
		}
		// 注入动态配置属性-root日志级别
		if (StringUtils.isNotBlank(rootLoggerLevel)) {
			System.setProperty(ROOTLOGGER_LEVEL, rootLoggerLevel.trim());
		}
		// 注入动态配置属性-文件分隔大小
		if (StringUtils.isNotBlank(maxFileSize)) {
			System.setProperty(MAXFILESIZE, maxFileSize.trim());
		}
		try {
			URL url = getURL(logbackConfigLocation);
			LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder
					.getSingleton().getLoggerFactory();
			// in the current version logback automatically configures at
			// startup
			// the context, so we have to reset it
			loggerContext.reset();
			// reinitialize the logger context. calling this method allows
			// configuration through groovy or xml
			new ContextInitializer(loggerContext).configureByResource(url);
		} catch (FileNotFoundException ex) {
			System.err.println("No logback configuration file found at ["
					+ logbackConfigLocation + "]");
			// throw new
			// IllegalArgumentException("Invalid 'logbackConfigLocation'
			// parameter: "
			// + ex.getMessage());
		} catch (JoranException e) {
			throw new RuntimeException(
					"Unexpected error while configuring logback", e);
		}

	}

	public void destory() {
		ContextSelector selector = ContextSelectorStaticBinder.getSingleton()
				.getContextSelector();
		LoggerContext loggerContext = selector.getLoggerContext();
		String loggerContextName = loggerContext.getName();
		LoggerContext context = selector.detachLoggerContext(loggerContextName);
		context.reset();
	}

	/**
	 * Resolve the given resource location to a {@code java.net.URL}.
	 * <p>
	 * Does not check whether the URL actually exists; simply returns the URL
	 * that the given location would correspond to.
	 * 
	 * @param resourceLocation
	 *            the resource location to resolve: either a "classpath:" pseudo
	 *            URL, a "file:" URL, or a plain file path
	 * @return a corresponding URL object
	 * @throws FileNotFoundException
	 *             if the resource cannot be resolved to a URL
	 */
	private static URL getURL(String resourceLocation)
			throws FileNotFoundException {
		if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
			String path = resourceLocation
					.substring(CLASSPATH_URL_PREFIX.length());
			URL url = Thread.currentThread().getContextClassLoader()
					.getResource(path);
			if (url == null) {
				String description = "class path resource [" + path + "]";
				throw new FileNotFoundException(description
						+ " cannot be resolved to URL because it does not exist");
			}
			return url;
		}
		try {
			// try URL
			return new URL(resourceLocation);
		} catch (MalformedURLException ex) {
			// no URL -> treat as file path
			try {
				return new File(resourceLocation).toURI().toURL();
			} catch (MalformedURLException ex2) {
				throw new FileNotFoundException("Resource location ["
						+ resourceLocation
						+ "] is neither a URL not a well-formed file path");
			}
		}
	}
}